"""
性能优化工具
"""

import asyncio
import time
import functools
from typing import Dict, Any, Callable, Optional
from collections import defaultdict, deque

from ..logger import logger


class PerformanceMonitor:
    """性能监控器"""
    
    def __init__(self, max_records: int = 1000):
        self.max_records = max_records
        self.metrics = defaultdict(deque)
        self.counters = defaultdict(int)
        
    def record_timing(self, operation: str, duration: float):
        """记录操作耗时"""
        self.metrics[f"{operation}_timing"].append({
            "duration": duration,
            "timestamp": time.time()
        })
        
        # 限制记录数量
        if len(self.metrics[f"{operation}_timing"]) > self.max_records:
            self.metrics[f"{operation}_timing"].popleft()
    
    def increment_counter(self, counter_name: str, value: int = 1):
        """增加计数器"""
        self.counters[counter_name] += value
    
    def get_stats(self) -> Dict[str, Any]:
        """获取统计信息"""
        stats = {
            "counters": dict(self.counters),
            "timings": {}
        }
        
        for key, records in self.metrics.items():
            if "_timing" in key:
                operation = key.replace("_timing", "")
                durations = [r["duration"] for r in records]
                
                if durations:
                    stats["timings"][operation] = {
                        "count": len(durations),
                        "avg": sum(durations) / len(durations),
                        "min": min(durations),
                        "max": max(durations),
                        "recent": durations[-10:] if len(durations) >= 10 else durations
                    }
        
        return stats


# 全局性能监控器
performance_monitor = PerformanceMonitor()


def timing_decorator(operation_name: str):
    """计时装饰器"""
    def decorator(func: Callable):
        @functools.wraps(func)
        async def async_wrapper(*args, **kwargs):
            start_time = time.time()
            try:
                result = await func(*args, **kwargs)
                return result
            finally:
                duration = time.time() - start_time
                performance_monitor.record_timing(operation_name, duration)
                
                if duration > 1.0:  # 记录慢操作
                    logger.warning(f"Slow operation: {operation_name} took {duration:.3f}s")
        
        @functools.wraps(func)
        def sync_wrapper(*args, **kwargs):
            start_time = time.time()
            try:
                result = func(*args, **kwargs)
                return result
            finally:
                duration = time.time() - start_time
                performance_monitor.record_timing(operation_name, duration)
                
                if duration > 1.0:
                    logger.warning(f"Slow operation: {operation_name} took {duration:.3f}s")
        
        return async_wrapper if asyncio.iscoroutinefunction(func) else sync_wrapper
    
    return decorator


class CircuitBreaker:
    """熔断器"""
    
    def __init__(
        self,
        failure_threshold: int = 5,
        recovery_timeout: float = 60.0,
        expected_exception: type = Exception
    ):
        self.failure_threshold = failure_threshold
        self.recovery_timeout = recovery_timeout
        self.expected_exception = expected_exception
        
        self.failure_count = 0
        self.last_failure_time = None
        self.state = "CLOSED"  # CLOSED, OPEN, HALF_OPEN
    
    def __call__(self, func: Callable):
        @functools.wraps(func)
        async def async_wrapper(*args, **kwargs):
            if self.state == "OPEN":
                if self._should_attempt_reset():
                    self.state = "HALF_OPEN"
                else:
                    raise Exception(f"Circuit breaker is OPEN for {func.__name__}")
            
            try:
                result = await func(*args, **kwargs)
                self._on_success()
                return result
            except self.expected_exception as e:
                self._on_failure()
                raise e
        
        @functools.wraps(func)
        def sync_wrapper(*args, **kwargs):
            if self.state == "OPEN":
                if self._should_attempt_reset():
                    self.state = "HALF_OPEN"
                else:
                    raise Exception(f"Circuit breaker is OPEN for {func.__name__}")
            
            try:
                result = func(*args, **kwargs)
                self._on_success()
                return result
            except self.expected_exception as e:
                self._on_failure()
                raise e
        
        return async_wrapper if asyncio.iscoroutinefunction(func) else sync_wrapper
    
    def _should_attempt_reset(self) -> bool:
        """检查是否应该尝试重置"""
        return (
            self.last_failure_time and
            time.time() - self.last_failure_time >= self.recovery_timeout
        )
    
    def _on_success(self):
        """成功时的处理"""
        self.failure_count = 0
        self.state = "CLOSED"
    
    def _on_failure(self):
        """失败时的处理"""
        self.failure_count += 1
        self.last_failure_time = time.time()
        
        if self.failure_count >= self.failure_threshold:
            self.state = "OPEN"
            logger.warning(f"Circuit breaker opened after {self.failure_count} failures")


class AsyncCache:
    """异步缓存"""
    
    def __init__(self, ttl: float = 300.0, max_size: int = 1000):
        self.ttl = ttl
        self.max_size = max_size
        self.cache = {}
        self.access_times = {}
    
    def __call__(self, func: Callable):
        @functools.wraps(func)
        async def wrapper(*args, **kwargs):
            # 生成缓存键
            cache_key = self._generate_key(func.__name__, args, kwargs)
            
            # 检查缓存
            if cache_key in self.cache:
                value, timestamp = self.cache[cache_key]
                if time.time() - timestamp < self.ttl:
                    self.access_times[cache_key] = time.time()
                    return value
                else:
                    # 过期，删除
                    del self.cache[cache_key]
                    del self.access_times[cache_key]
            
            # 执行函数
            result = await func(*args, **kwargs)
            
            # 存储到缓存
            self._store(cache_key, result)
            
            return result
        
        return wrapper
    
    def _generate_key(self, func_name: str, args: tuple, kwargs: dict) -> str:
        """生成缓存键"""
        import hashlib
        key_data = f"{func_name}:{str(args)}:{str(sorted(kwargs.items()))}"
        return hashlib.md5(key_data.encode()).hexdigest()
    
    def _store(self, key: str, value: Any):
        """存储到缓存"""
        current_time = time.time()
        
        # 检查缓存大小
        if len(self.cache) >= self.max_size:
            self._evict_oldest()
        
        self.cache[key] = (value, current_time)
        self.access_times[key] = current_time
    
    def _evict_oldest(self):
        """淘汰最旧的缓存项"""
        if not self.access_times:
            return
        
        oldest_key = min(self.access_times.keys(), key=lambda k: self.access_times[k])
        del self.cache[oldest_key]
        del self.access_times[oldest_key]
    
    def clear(self):
        """清空缓存"""
        self.cache.clear()
        self.access_times.clear()
    
    def get_stats(self) -> Dict[str, Any]:
        """获取缓存统计"""
        current_time = time.time()
        valid_items = sum(
            1 for _, timestamp in self.cache.values()
            if current_time - timestamp < self.ttl
        )
        
        return {
            "total_items": len(self.cache),
            "valid_items": valid_items,
            "hit_rate": 0.0,  # 需要额外跟踪命中率
            "max_size": self.max_size,
            "ttl": self.ttl
        }


class ConnectionPool:
    """连接池"""
    
    def __init__(self, max_connections: int = 10):
        self.max_connections = max_connections
        self.pool = asyncio.Queue(maxsize=max_connections)
        self.active_connections = 0
        self._lock = asyncio.Lock()
    
    async def acquire(self):
        """获取连接"""
        try:
            # 尝试从池中获取连接
            connection = self.pool.get_nowait()
            return connection
        except asyncio.QueueEmpty:
            # 池为空，创建新连接
            async with self._lock:
                if self.active_connections < self.max_connections:
                    connection = await self._create_connection()
                    self.active_connections += 1
                    return connection
                else:
                    # 等待连接可用
                    return await self.pool.get()
    
    async def release(self, connection):
        """释放连接"""
        try:
            self.pool.put_nowait(connection)
        except asyncio.QueueFull:
            # 池已满，关闭连接
            await self._close_connection(connection)
            async with self._lock:
                self.active_connections -= 1
    
    async def _create_connection(self):
        """创建新连接（子类实现）"""
        return {"id": time.time(), "created": time.time()}
    
    async def _close_connection(self, connection):
        """关闭连接（子类实现）"""
        pass
    
    async def close_all(self):
        """关闭所有连接"""
        while not self.pool.empty():
            try:
                connection = self.pool.get_nowait()
                await self._close_connection(connection)
            except asyncio.QueueEmpty:
                break
        
        self.active_connections = 0


# 创建全局实例
cache = AsyncCache(ttl=300.0, max_size=1000)
circuit_breaker = CircuitBreaker(failure_threshold=5, recovery_timeout=60.0)
